//
//  EXTransaction.m
//  ORM
//
//  Created by PH on 21.12.09.
//  Copyright 2009-2010 Codesign. All rights reserved.
//

#import "EXTransaction.h"
#import "EXObjectStore.h"

@implementation EXTransaction

@synthesize processedObjectsForReading;
@synthesize processedObjectsForWriting;
@synthesize proxies;
@synthesize delegate;
@synthesize began;

- (id)initWithObjectStore:(EXObjectStore*)_objectStore {
	if ((self = [super init])) {
		objectStore = _objectStore;
		processedObjectsForReading = [[NSMutableDictionary alloc] init];
		processedObjectsForWriting = [[NSMutableSet alloc] init];
		proxies = [[NSMutableDictionary alloc] init];
	}
	return self;
}

- (BOOL)commit {
	if ([delegate respondsToSelector: @selector(didCommitTransaction:)])
		[delegate performSelector: @selector(didCommitTransaction:) withObject: self];
	if ([objectStore.delegate respondsToSelector: @selector(didCommitTransaction:)])
		[objectStore.delegate performSelector: @selector(didCommitTransaction:) withObject: objectStore];
	[[objectStore.currentTransaction retain] autorelease];
	objectStore.currentTransaction = nil;
	NSAssert(objectStore != nil && [objectStore KVStore] != nil, @"Object store in transaction or its KVStore is nil");
	return [[objectStore KVStore] commitTransaction];
}

- (BOOL)rollback {
	if ([delegate respondsToSelector: @selector(didRollbackTransaction:)])
		[delegate performSelector: @selector(didRollbackTransaction:) withObject: self];
	if ([objectStore.delegate respondsToSelector: @selector(didRollbackTransaction:)])
		[objectStore.delegate performSelector: @selector(didRollbackTransaction:) withObject: objectStore];
	[[objectStore.currentTransaction retain] autorelease];
	objectStore.currentTransaction = nil;
	NSAssert(objectStore != nil && [objectStore KVStore] != nil, @"Object store in transaction or its KVStore is nil");
	return [[objectStore KVStore] rollbackTransaction];
}

- (void)begin {
	if (began == NO) {
		began = YES;
		if ([delegate respondsToSelector: @selector(didBeginTransaction:)])
			[delegate performSelector: @selector(didBeginTransaction:) withObject: self];
	}
}

- (BOOL)storeObject:(NSObject<EXMappableObject>*)object {
	[self begin];
	BOOL success = [objectStore storeObject: object createTransaction: NO processedObjects: processedObjectsForWriting];
	return success;
}

- (BOOL)removeObject:(NSObject<EXMappableObject>*)object {
	[self begin];
	return [objectStore removeObject: object createTransaction: NO];
}

- (id)objectWithObjectID:(NSString*)objectID {
	return [objectStore objectWithObjectID: objectID lazyCollections: NO createTransaction: NO processedObjects: processedObjectsForReading];
}

- (NSArray*)objectsOfClass:(Class)cls {
	[self begin];
	NSMutableArray* results = [NSMutableArray array];
	[objectStore objectsOfClass: cls createTransaction: NO includeSubclasses: YES results: results processedObjects: processedObjectsForReading];
	return results;
}

- (NSArray*)objectsOfClass:(Class)cls filter:(EXQuery*)query {
	[self begin];
	return [objectStore	objectsOfClass: cls filter: query createTransaction: NO];
}

- (NSArray*)proxiesOfClass:(Class)cls {
	[self begin];
	NSMutableArray* results = [NSMutableArray array];
	[objectStore proxiesOfClass: cls createTransaction: NO includeSubclasses: YES results: results proxies: proxies condBlock: nil];
	return results;
}

- (NSArray*)objectsWithPredicate:(EXPredicate*)predicate {
	[self begin];
	return [objectStore objectsWithPredicate: predicate createTransaction: NO processedObjects: processedObjectsForReading];
}

- (NSArray*)proxiesWithPredicate:(EXPredicate*)predicate {
	[self begin];
	if (predicate.filterBlock != nil) {
		NSArray* results = [self proxiesOfClass: [predicate predicateClass]];
		NSMutableArray* filteredResults = [NSMutableArray array];
		for (id object in results) {
			if (predicate.filterBlock(object) == YES) [filteredResults addObject: object];
		}
		return filteredResults;
	} else {
		[self begin];
		NSMutableArray* results = [NSMutableArray array];
		[objectStore proxiesOfClass: [predicate predicateClass] createTransaction: NO includeSubclasses: YES results: results proxies: proxies condBlock: [predicate condBlock]];
		return results;
	}
}

- (void)dealloc {
	[processedObjectsForReading release];
	[processedObjectsForWriting release];
	[proxies release];
	[delegate release];
	[super dealloc];
}

@end
